package com.shloma.bbts.tcp;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.shloma.bbts.entity.SysConfig;
import com.shloma.bbts.service.SysConfigService;
import com.shloma.bbts.utils.BeanFactoryUtils;

@Service
public class TcpServer implements Runnable {

	private static Logger logger = LoggerFactory.getLogger(TcpServer.class);

	private Selector selector;
	private ServerSocketChannel serverSocketChannel;

	private boolean running = false;

	public void startServer() {
		logger.info(">>>>> 启动TCP服务开始");
		running = true;
		new Thread(this).start();
		logger.info(">>>>> 启动TCP服务结束");
	}

	public void stopServer() {
		logger.info(">>>>> 停止TCP服务开始");
		running = false;
		try {
			if (serverSocketChannel != null) {
				serverSocketChannel.close();
			}
			if (selector != null) {
				selector.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		logger.info(">>>>> 停止TCP服务开始");
	}

	public TcpServer() {

	}

	@SuppressWarnings("rawtypes")
	@Override
	public void run() {
		
		SysConfigService configService = BeanFactoryUtils.getBean(SysConfigService.class);
		SysConfig querySysConfig = configService.querySysConfig();
		
		try {
			selector = Selector.open();
			serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.socket().bind(new InetSocketAddress(querySysConfig.getBankServerPort()));
			serverSocketChannel.configureBlocking(false);
			SelectionKey selectionKey0 = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
			selectionKey0.attach(new Acceptor());

			System.out.println("--------TcpServer-run");
			while (running) {
				System.out.println("--------TcpServer-while1");
				selector.select(5000 * 1001);
				if (selector.isOpen()) {
					Set selected = selector.selectedKeys();
					Iterator it = selected.iterator();
					while (it.hasNext()) {
						System.out.println("--------TcpServer-while2");
						dispatch((SelectionKey) (it.next()));
					}
					selected.clear();
				}
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	void dispatch(SelectionKey k) {
		Runnable r = (Runnable) (k.attachment());
		System.out.println("--------dispatch=" + r);
		if (r != null) {
			r.run();
		}
	}

	class Acceptor implements Runnable {
		public void run() {
			System.out.println("--------Acceptor");
			try {
				SocketChannel socketChannel = serverSocketChannel.accept();
				if (socketChannel != null) {
					new Handler(selector, socketChannel);
				}
				System.out.println("Connection Accepted by Reactor");
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}

	class Handler implements Runnable {
		final SocketChannel socketChannel;
		final SelectionKey selectionKey;
		ByteBuffer input = ByteBuffer.allocate(1024);
		static final int READING = 0, SENDING = 1;
		int state = READING;
		String clientName = "";

		Handler(Selector selector, SocketChannel c) throws IOException {
			socketChannel = c;
			c.configureBlocking(false);
			selectionKey = socketChannel.register(selector, 0);
			selectionKey.attach(this);
			selectionKey.interestOps(SelectionKey.OP_READ);
			selector.wakeup();
		}

		@SuppressWarnings("resource")
		@Override
		public void run() {
			System.out.println("--------Handler");
			if (state == READING) {
				// read();
			} else if (state == SENDING) {
				// send();
			}

			ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
			ByteBuffer bb = ByteBuffer.allocate(1024);
			String input1 = "";
			try {
				input1 = new String(byteArrayOutputStream.toByteArray(), "GBK");
			} catch (UnsupportedEncodingException e1) {
				e1.printStackTrace();
			}
			System.out.println("receive data1: " + input1);
			try {
				int readSize = 0;
				while ((readSize = socketChannel.read(bb)) > 0) {
					// 读写转换
					bb.flip();
					byteArrayOutputStream.write(bb.array(), 0, readSize);
				}

				byteArrayOutputStream.flush();

				String input = new String(byteArrayOutputStream.toByteArray(), "GBK");
				RandomAccessFile accessFile = new RandomAccessFile(new File("./aa.txt"), "rw");
				accessFile.write(input.getBytes());
				System.out.println("receive data2: " + input);

				// byteArrayOutputStream.reset();
				if ("exit".equals(input)) {
					serverSocketChannel.close();
					selector.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			try {

				byte[] rsp = "succcesssucccesssucccesssucccesssucccesssucccesssucccesssucccesssucccesssucccesssucccesssucccesssucccesssucccesssucccess22"
						.getBytes();
				ByteBuffer buf = ByteBuffer.allocate(rsp.length);
				buf.clear();
				buf.put(rsp);
				buf.flip();
				while (buf.hasRemaining()) {
					socketChannel.write(buf);
				}

				socketChannel.finishConnect();
				socketChannel.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			// selectionKey.

			// selector.
		}
	}

}
